package com.gitee.springboot.firstlesson;

import com.gitee.springboot.firstlesson.config.BookSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.context.WebServerApplicationContext;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

/**
 * 该类是和JarLauncher是处于同一进程还是属于JarLauncher的子进程?
 * 在不加入webflux之前,使用spring-boot-starter-web + 使用undertow容器 + application.properties文件配置=>http2.0
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@RestController
public class FirstlessonApplication implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
    private static final Logger logger = LoggerFactory.getLogger(FirstlessonApplication.class);
    public static void main(String[] args) {
//        runDirect(args);
        startWithoutBanner(args);
    }

    public static void runDirect(String[] args){
        SpringApplication.run(FirstlessonApplication.class, args);
    }

    /**
     * 关闭banner
     * @param args
     */
    public static void startWithoutBanner(String[] args){
        SpringApplication app = new SpringApplication(FirstlessonApplication.class);
        app.setBannerMode(Banner.Mode.OFF);
        //completely disable restart support
        //System.setProperty("spring.devtools.restart.enabled","false");
        app.run(args);
    }

    @Autowired
    private BookSettings bookSettings;

    @Value("${test.test001}")
    private String test001;

    //@Autowired
    //private HelloService helloService;

    @GetMapping("/hello")
    public String sayHello(){
        logger.info("book.name:"+bookSettings.getName());
        //return helloService.sayHello();
        System.out.println(test001);
        return "hello world!";
    }

    @Bean
    public RouterFunction<ServerResponse> helloWorld(){
        return route(GET("/helloworld"),
                request->ok().body(Mono.just("hello webflux"),String.class));
    }

    @Override
    public void customize(UndertowServletWebServerFactory factory) {
        factory.addBuilderCustomizers(builder->{
            builder.addHttpListener(8080,"0.0.0.0");
        });
    }

    /**
     * 利用ApplicationRunner Bean的特性,其run(ApplicationArguments)方法在SpringBoot应用启动后回调.
     * 当前这种方式虽然能够获取到相应的实例,但是这种实现方式并不健壮,原因是在ApplicationRunner@Bean方法声明时,
     * 该方法注入了WebServerApplicationContext,这种写法可以兼顾Reactive和Servlet场景,但是却没有覆盖非Web
     * 应用类型的场景.
     * @param context
     * @return
     */
    public ApplicationRunner runner(WebServerApplicationContext context){

        return args -> {
            System.out.println("当前webServer的实现类:"+ context.getWebServer().getClass().getName());
        };
    }

    /**
     * 为了解决runner方法中的覆盖面不足问题,SpringBoot在架构设计层提供了兼容性更强的方案,即Web服务器已初始化事件
     * WebServerInitalizedEvent.
     * 即使在非Web应用中运行,也不至注入WebServerApplicationContext失败 切换Reactive容器到jetty也是可以的.
     * @param event
     */
    @EventListener(WebServerInitializedEvent.class)
    public void onWebServerReady(WebServerInitializedEvent event){
        System.out.println("当前WebServer实现类为:" + event.getWebServer().getClass().getName());
        System.out.println("当前WebServer端口为:" + event.getWebServer().getPort());
    }


}
